home *** CD-ROM | disk | FTP | other *** search
/ Light ROM 1 / LIGHT-ROM 1 (Amiga Library Services)(1994).iso / ffdisks / d939.lha / ExtraCmds / source_etc.lha / src / Split.c < prev    next >
C/C++ Source or Header  |  1993-10-22  |  9KB  |  343 lines

  1. /*   ---------------------------------      -------     
  2.  *   |\  | | | | |  |.| |   \|  |/ /|\      |||||||     
  3.  *   | | | |/  | |\ |/  |/|  |\ |/  |    ?  ---+---  =< 
  4.  *   | | | |   | |  |     |  |  |   |     \qqqqqqqqq/   
  5.  *   ---------------------------------  ~~~~~~~~~~~~~~~~
  6.  *  Split - Split a file into pieces. 
  7.  *  Copyright (C) 1989, 1992, 1993 Torsten Poulin
  8.  *
  9.  *  This program is free software; you can redistribute it and/or modify
  10.  *  it under the terms of the GNU General Public Licence as published by
  11.  *  the Free Software Foundation; either version 2 of the Licence, or
  12.  *  (at your option) any later version.
  13.  *
  14.  *  This program is distributed in the hope that it will be useful,
  15.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  *  GNU General Public Licence for more details.
  18.  *
  19.  *  You should have received a copy of the GNU General Public Licence
  20.  *  along with this program; if not, write to the Free Software
  21.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  *
  23.  *  The author can be contacted by s-mail at
  24.  *    Torsten Poulin
  25.  *    Banebrinken 99, 2, 77
  26.  *    DK-2400 Copenhagen NV
  27.  *    DENMARK
  28.  *
  29.  * $Id: Split.c,v 37.5 93/03/30 23:12:33 Torsten Rel $
  30.  * $Log:    Split.c,v $
  31.  * Revision 37.5  93/03/30  23:12:33  Torsten
  32.  * Rewritten from scratch. The code is a lot easier to maintain
  33.  * and improve now. An informal test showed that byte oriented
  34.  * splits (BYTES and PARTS) are approx. 10-35 times faster than before.
  35.  * The line oriented mode hasn't been optimized yet.
  36.  * The price to be paid is an 80% bigger executable (still smaller
  37.  * than 2kb though ;-).
  38.  * The 28 character limit on the TO name has been raised to 253.
  39.  * Important: The template has been changed!!!
  40.  * 
  41.  * Revision 37.4  93/02/13  16:13:10  Torsten
  42.  * Replaced exec.library/SetSignal() with dos.library/CheckSignal().
  43.  * 
  44.  */
  45.  
  46. #include <exec/types.h>
  47. #include <exec/memory.h>
  48. #include <dos/dos.h>
  49. #include <dos/dostags.h>
  50. #include <clib/macros.h>
  51. #include <clib/dos_protos.h>
  52. #include <clib/exec_protos.h>
  53. #ifdef __SASC
  54. #include <pragmas/dos_pragmas.h>
  55. #include <pragmas/exec_pragmas.h>
  56. #endif
  57. #include <string.h>
  58. #include "tastlib.h"
  59. #include "split_rev.h"
  60.  
  61. #define SPLITBUFSIZE 51200L
  62.  
  63. #define PROGNAME "Split"
  64. #define TEMPLATE "FROM,TO/K,LINES/K/N,BYTES/K/N,PARTS/K/N,PROMPT/S"
  65. #define OPT_FROM   0
  66. #define OPT_TO     1
  67. #define OPT_LINES  2
  68. #define OPT_BYTES  3
  69. #define OPT_PARTS  4
  70. #define OPT_PROMPT 5
  71.  
  72. typedef struct {
  73.   struct DosLibrary *DOSBase;
  74.   struct FileInfoBlock fib;
  75.   BOOL prompt;
  76.   LONG type;
  77.   LONG number;
  78.   UBYTE outname[256], *ext2, *ext1;
  79.   /* a future version will automatically try smaller buffers if necessary */
  80.   UBYTE buffer[SPLITBUFSIZE];
  81.   LONG  bufsize;
  82. } Global;
  83.  
  84. char const versionID[] = VERSTAG;
  85. char const copyright[] = "$COPYRIGHT:©1989,1992,1993 Torsten Poulin$";
  86.  
  87. LONG getnumber(LONG);
  88. VOID initoutname(UBYTE *, Global *);
  89. VOID incoutname(Global *);
  90. LONG split(BPTR, Global *);
  91. LONG copylines(BPTR, BPTR, LONG, Global *);
  92. LONG copybytes(BPTR, BPTR, LONG, Global *);
  93. VOID promptuser(Global *);
  94.  
  95.  
  96. LONG entrypoint(VOID)
  97. {
  98.   struct DosLibrary *DOSBase;
  99.   struct RDArgs     *args;
  100.   Global *global;
  101.   LONG   arg[6];
  102.   LONG   rc = RETURN_OK;
  103.   BPTR   input;
  104.  
  105.   if (!(DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 37L)))
  106.     return RETURN_FAIL;
  107.  
  108.   if (!(global = AllocVec(sizeof(Global), MEMF_CLEAR)))
  109.     rc = ERROR_NO_FREE_STORE;
  110.   else
  111.   {
  112.     global->DOSBase = DOSBase;
  113.     global->bufsize = SPLITBUFSIZE;
  114.  
  115.     arg[OPT_FROM] = arg[OPT_TO] = arg[OPT_LINES] =
  116.       arg[OPT_PARTS] = arg[OPT_BYTES] = arg[OPT_PROMPT] = 0L;
  117.     
  118.     if (!(args = ReadArgs(TEMPLATE, arg, NULL)))
  119.       rc = RETURN_FAIL;
  120.     else
  121.     {
  122.       initoutname(arg[OPT_TO] ? (UBYTE *) arg[OPT_TO] : "x", global);
  123.       global->prompt = (BOOL) arg[OPT_PROMPT];
  124.  
  125.       if (arg[OPT_PARTS])
  126.       {
  127.     global->type = OPT_PARTS;
  128.     global->number = getnumber(arg[OPT_PARTS]);
  129.       }
  130.       else if (arg[OPT_BYTES])
  131.       {
  132.     global->type = OPT_BYTES;
  133.     global->number = getnumber(arg[OPT_BYTES]);
  134.       }
  135.       else if (arg[OPT_LINES])
  136.       {
  137.     global->type = OPT_LINES;
  138.     global->number = getnumber(arg[OPT_LINES]);
  139.       }
  140.       else
  141.       {
  142.     global->type = OPT_LINES;
  143.     global->number = 1000;
  144.       }
  145.  
  146.       if (!arg[OPT_FROM])
  147.     rc = split(Input(), global);
  148.       else if (input = Open((UBYTE *) arg[OPT_FROM], MODE_OLDFILE))
  149.       {
  150.     rc = split(input, global);
  151.     Close(input);
  152.       }
  153.       else
  154.     rc = RETURN_ERROR;
  155.  
  156.       FreeArgs(args);
  157.     }
  158.     FreeVec(global);
  159.   }
  160.   rc = printErrorMsg(rc, PROGNAME, DOSBase);
  161.   CloseLibrary((struct Library *) DOSBase);
  162.   return rc;
  163. }
  164.  
  165.  
  166. LONG getnumber(LONG val)
  167. {
  168.   LONG number;
  169.  
  170.   number = *(ULONG *) val;
  171.   if (number < 1L)
  172.     number = 1L;
  173.   return number;
  174. }
  175.  
  176.  
  177. VOID initoutname(UBYTE *name, Global *global)
  178. {
  179.   UBYTE *p = global->outname;
  180.   LONG len;
  181.  
  182.   for (len = 0; *name && len < 253; len++, name++)
  183.     *p++ = *name;
  184.   global->ext1 = p;
  185.   *p++ = 'a';
  186.   global->ext2 = p;
  187.   *p++ = 'a';
  188.   *p = '\0';
  189. }
  190.  
  191.  
  192. VOID incoutname(Global *global)
  193. {
  194.   if (*global->ext2 < 'z')
  195.     ++*global->ext2;
  196.   else
  197.   {
  198.     *global->ext2 = 'a';
  199.     ++*global->ext1;
  200.   }
  201. }
  202.  
  203.  
  204. LONG split(BPTR input, Global *global)
  205. {
  206.   struct DosLibrary *DOSBase = global->DOSBase;
  207.   LONG (*copy)(BPTR in, BPTR out, LONG number, Global *global);
  208.   LONG rc = RETURN_OK;
  209.   LONG count = 0;
  210.   BPTR output;
  211.  
  212.   if (global->type == OPT_PARTS)
  213.   {
  214.     /* To use PARTS we  obviously  need  to know how long the file is.
  215.      * Previous versions of this program used Seek() to  determine the
  216.      * length. This led to very unhappy results if  the input happened
  217.      * to be a  pipe.  In  my humble  opinion  pipes either  shouldn't
  218.      * support  the  ACTION_SEEK  packet, or  better  when  supporting
  219.      * ACTION_EXAMINE_OBJECT  should   set   the  fib_DirEntryType  to
  220.      * something like  ST_PIPE or whatever (to be honest  the  various
  221.      * pipe handlers I have actually do that: William Hawes' PIP: sets
  222.      * it to -5.   C-A's PIPE: and  Matt Dillon's FIFO: set it to  0).
  223.      * How about creating an official (documented) standard?  So given
  224.      * the present circumstances the following, though not without its
  225.      * flaws, works a little better.
  226.      */
  227.     if (!ExamineFH(input, &global->fib)
  228.     || global->fib.fib_Size == 0
  229.     || global->fib.fib_DirEntryType == -5
  230.     || global->fib.fib_DirEntryType == 0)
  231.     {
  232.       MyPrintf(global,
  233.            "%s: Cannot determine size (file is a pipe or empty)\n",
  234.            PROGNAME);
  235.       SetIoErr(ERROR_OBJECT_WRONG_TYPE);
  236.       return RETURN_ERROR;
  237.     }
  238.     else
  239.     {
  240.       if (global->number > 676)
  241.     global->number = 676;
  242.       global->number = global->fib.fib_Size / global->number + 1;
  243.     }
  244.   }
  245.  
  246.   if (global->type == OPT_LINES)
  247.     copy = copylines;
  248.   else
  249.     copy = copybytes;
  250.  
  251.   while (rc == RETURN_OK)
  252.   {
  253.     count++;
  254.     if (count == 676)
  255.       global->number = -1;
  256.  
  257.     if (global->prompt)
  258.       promptuser(global);
  259.  
  260.     if (!(output = Open(global->outname, MODE_NEWFILE)))
  261.     {
  262.       MyPrintf(global, "%s: Cannot open %s\n", PROGNAME, global->outname);
  263.       return RETURN_ERROR;
  264.     }
  265.     rc = copy(input, output, global->number, global);
  266.     Close(output);
  267.     incoutname(global);
  268.   }
  269.   if (rc == EOF)
  270.     rc = RETURN_OK;
  271.   return rc;
  272. }
  273.  
  274.  
  275. LONG copylines(BPTR in, BPTR out, LONG number, Global *global)
  276. {
  277.   struct DosLibrary *DOSBase = global->DOSBase;
  278.   register UBYTE breakcheck = 0;
  279.   LONG count = 0;
  280.   LONG c;
  281.  
  282.   while ((c = FGetC(in)) != EOF)
  283.   {
  284.     if (FPutC(out, c) == EOF)
  285.       return RETURN_ERROR;
  286.     if (c == '\n')
  287.     {
  288.       count++;
  289.       if (count == number)
  290.     return RETURN_OK;
  291.     }
  292.     if (!(breakcheck -= 4) && CheckSignal(SIGBREAKF_CTRL_C))
  293.       return ERROR_BREAK;
  294.   }
  295.   return EOF;
  296. }
  297.  
  298.  
  299. LONG copybytes(BPTR in, BPTR out, LONG number, Global *global)
  300. {
  301.   struct DosLibrary *DOSBase = global->DOSBase;
  302.   LONG wrote, read;
  303.   LONG bytes;
  304.   BOOL to_end = number < 0;
  305.  
  306.   bytes = to_end ? global->bufsize : MIN(global->bufsize, number);
  307.   wrote = 1;
  308.   while ((read = Read(in, global->buffer, bytes)) > 0 && wrote > 0)
  309.   {
  310.     wrote = Write(out, global->buffer, read);
  311.     if (!to_end)
  312.     {
  313.       if ((number -= read) == 0)
  314.     break;
  315.       bytes = MIN(global->bufsize, number);
  316.     }
  317.     if (CheckSignal(SIGBREAKF_CTRL_C))
  318.       return ERROR_BREAK;
  319.   }
  320.   
  321.   if (read < 0 || wrote < 0)
  322.     return RETURN_ERROR;
  323.   else if (read == 0)
  324.     return EOF;
  325.   else
  326.     return RETURN_OK;
  327. }
  328.  
  329.  
  330. VOID promptuser(Global *global)
  331. {
  332.   struct DosLibrary *DOSBase = global->DOSBase;
  333.   BPTR console;
  334.                         
  335.   MyPrintf(global, "Press RETURN to write %s", global->outname);
  336.   Flush(Output());
  337.   if (console = Open("CONSOLE:", MODE_OLDFILE))
  338.   {
  339.     FGetC(console);
  340.     Close(console);
  341.   }
  342. }
  343.